package com.study.threadpool.helper;

import org.omg.PortableServer.ThreadPolicy;
import org.springframework.stereotype.Component;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author flwu
 * @date 2020/3/11 5:25 PM
 * @MOTTO 保持空和敬畏
 */
public class ThreadPoolHelper {

    private final static int DEFAULT_CORE_POOL_SIZE = 2;
    private final static int DEFAULT_MAX_POOL_SIZE = 10;
    private final static int DEFAULT_KEEP_ALIVE_TIME = 1;
    private final static int DEFAULT_MAX_QUEUE_COUNT = 10;

    /**
     * 构建线程池(默认参数)
     * @param threadName
     * @return
     *
     * desc:
     * 【policy拒绝策略：】
     *      CallerRunsPolicy 这个策略重试添加当前任务，他会自动重复调用execute()方法，直到成功
     *      AbortPolicy 对拒绝任务抛弃处理，并且抛出异常
     *      DiscardPolicy 对拒绝任务直接无声抛弃，没有异常信息
     *      DiscardOldestPolicy 对拒绝任务不抛弃，而是抛弃队列里面等待最久的一个线程，然后把拒绝任务添加到队里中
     * 【线程池工作原理：】
     *     当一个任务通过 execute(Runnable) 方法欲添加到线程池时，线程池采用的策略如下：
     *      1. 如果此时线程池中的数量小于 corePoolSize ，即使线程池中的线程都处于空闲状态，也要创建新的线程来处理被添加的任务。
     *      2. 如果此时线程池中的数量等于 corePoolSize ，但是缓冲队列 workQueue 未满，那么任务被放入缓冲队列。
     *      3. 如果此时线程池中的数量大于 corePoolSize ，缓冲队列 workQueue 满，并且线程池中的数量小于maximumPoolSize ，建新的线程来处理被添加的任务。
     *      4. 如果此时线程池中的数量大于 corePoolSize ，缓冲队列 workQueue 满，并且线程池中的数量等于maximumPoolSize ，那么通过 handler 所指定的策略来处理此任务。
     * 【线程池执行顺序：】
     *      优先核心线程corePoolSize、 任务队列workQueue、最大线程数maximumPoolSize、如果三个都满了，使用handler处理被拒绝的任务
     *      当线程池中的线程数大于corePoolSize，如果某个线程空闲时间超过keepAliveTime，线程将被终止，这样线程池可以动态的调整线程池中的线程数
     *
     */
    public static ThreadPoolExecutor createThreadPool(String threadName) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAX_POOL_SIZE,
                DEFAULT_KEEP_ALIVE_TIME, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(DEFAULT_MAX_QUEUE_COUNT),
                new ThreadFactory() {
            private AtomicLong atomicLong = new AtomicLong();

                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setName(threadName + atomicLong.getAndIncrement());
                        return thread;
                    }
                }, new ThreadPoolExecutor.AbortPolicy());
        return executor;
    }

    /**
     * 创建线程池[自定以参数]
     * @param name
     * @param corePoolSize
     * @param maxPoolSize
     * @param keepAliveTime
     * @param maxQueueCount
     * @return
     */
    public static ThreadPoolExecutor createThreadPool(String name, int corePoolSize, int maxPoolSize, int keepAliveTime, int maxQueueCount) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(maxPoolSize),
                new ThreadFactory() {
            AtomicLong atomicLong = new AtomicLong();
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread thread = new Thread(r);
                        thread.setName(name + atomicLong.getAndIncrement());
                        return thread;
                    }
                }, new ThreadPoolExecutor.AbortPolicy());
        return executor;
    }


}
